iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0

今天的主題:陣列(Array)

今天學的是「一群資料的容器」——陣列。宣告方式是用中括號:

const enemies = ["雜魚", "小怪", "菁英怪", "小BOSS", "魔王"];

索引從 0 開始,是經典 bug 來源

要拿出陣列裡的東西,用索引(index),但索引從 0 開始算,不是從 1:

console.log(enemies[0]);   // 雜魚
console.log(enemies[1]);   // 小怪
console.log(enemies[2]);   // 菁英怪

這個「從 0 開始」的習慣,業界有個專門的錯誤名稱叫 off-by-one error(差一錯誤)——新手很容易想成「第一個是 1」,結果拿錯資料或漏看最後一個。

不是所有語言都從 0 開始——這其實是兩種不同的邏輯

查了一下才知道,JavaScript 從 0 開始算索引,不是全世界的共識,像 Lua、MATLAB、R 這些語言,陣列的第一個位置就是索引 1,不是 0。這讓我想到一個比喻,可以解釋這兩種邏輯的差異:

從 0 開始,像爬樓梯:算的是「距離起點幾步」。 你在 1 樓,爬到 5 樓,實際上只爬了 4 層樓梯(1→2、2→3、3→4、4→5)。陣列的索引 0 代表「距離起點 0 步」,也就是第一個元素;索引 4 代表「距離起點 4 步」,也就是第五個元素。索引本質上是「位移量」,不是「第幾個」。

從 1 開始,像搭電梯:直接按你要的樓層數字。 你不用管實際爬了幾層樓梯,直接按下「5」就到 5 樓。這類語言的索引直接對應「第幾個」,不用换算位移。

JavaScript 選擇「爬樓梯」邏輯,是因為索引在電腦底層原本的意義,就是「從資料起始位置算起,要位移幾步才能找到這筆資料」——這是很多主流語言(C、Java、Python)共同的選擇,但不是唯一的選擇。

我一開始測得不夠精準,後來改用更犀利的邊界值

我原本試著取 enemies[100],想看看超出範圍會怎樣,結果是 undefined。但這個測法其實不夠精準——100 一看就知道超出範圍,沒有真正測到「差一點點就出界」的臨界點

改成測 enemies[5] 之後,結果更有意義:陣列有 5 個元素(索引 0 到 4),length 是 5,但 length 這個數字本身,剛好就是第一個不存在的索引。這個「差一個」的臨界點,才是新手最容易誤判的地方——很容易誤以為「陣列有 5 個,那索引應該到 5 吧」,結果 enemies[5] 其實是 undefined

插入 day5.png:enemies[100] 測試結果,含 [[Prototype]] 展開畫面

同一個索引,加一個元素之後就不一樣了

這裡我多做了一個實驗:先測一次 enemies[5](此時是 undefined),接著 push 一個新元素進去,再測一次同樣的 enemies[5]:

console.log(enemies[5]);        // push 之前:undefined
enemies.push("終極魔王");
console.log(enemies[5]);        // push 之後:終極魔王

同一行程式碼、同一個索引,因為陣列的內容變了,結果完全不同。這讓我更清楚體會到:陣列的「有效範圍」不是固定的,它會隨著 push 這類操作即時改變——今天的臨界點,明天可能就不是臨界點了。

插入 day5-2.png:enemies[5] 在 push 前後的不同結果

意外發現:[[Prototype]] 是什麼

展開 Console 裡的陣列時,我發現最後多了一行 [[Prototype]]: Array(0),查了才知道:陣列在 JavaScript 裡其實也是一種物件,而每個物件都帶著一條隱藏連結,指向一個「範本物件」,陣列的範本物件叫 Array.prototype——像 .push().length 這些功能,不是每個陣列自己各存一份,而是所有陣列共用同一份範本,透過這條隱藏連結去借用。

這個機制叫原型鏈(prototype chain),而且這條鏈不只一層:Array.prototype 自己也有一條 [[Prototype]],指向更基礎、所有物件都通用的 Object.prototype。用比喻理解就是:

你的陣列 → Array 部門手冊(Array.prototype) → 公司總手冊(Object.prototype)

不同的陣列預設都共用同一本「部門手冊」,不會各自長出不同版本;但不同種類的東西(陣列 vs 一般物件)所連結的手冊確實不一樣。這是比較進階的概念,現階段先知道「陣列的方法是透過這條隱藏連結借來的」就夠了。

小結

今天搞懂的事:

  • 陣列索引從 0 開始,length 是總數,但最後一個有效索引是 length - 1
  • 從 0 開始是「爬樓梯」邏輯(算位移量),從 1 開始是「搭電梯」邏輯(直接對應第幾個);JavaScript 選的是前者,但不是所有語言都一樣
  • 測邊界值要測「差一點點」的臨界點(像 length 本身),不是隨便取一個明顯超出範圍的數字
  • 陣列的有效範圍會隨著 push 這類操作即時改變,同一個索引在不同時間點可能有效也可能無效
  • 陣列的內建方法(pushlength)是透過 [[Prototype]] 這條隱藏連結,從共用的 Array.prototype 借來的

明天繼續學物件——遊戲角色資料要正式登場了。


上一篇
Day04|條件判斷與邊界測試:HP 剛好 30,算不算重傷?
下一篇
Day06|物件登場:const 鎖不住的內容,鎖不住的陣列
系列文
QA 的 JavaScript 初心之路:30 天做出一個能玩的戰鬥小遊戲《勇者 vs 小怪》7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言